﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DAL;
using System.Data;
using System.IO;
using System.Configuration;
using System.Transactions;
using System.Data.Linq;
using System.ComponentModel;
using UtilityExtensions;

namespace BOL
{
    [Serializable]
   public class KardexBL
    {
 #region " Cierre CRUD"

       public void AddCierre(short anio,
                              short mes,
                              int idAlmacen,
                              decimal tipoCambiodollarCierre,
                              string observacion)
       {
          



           SaldoKardex saldok = new SaldoKardex();
            

           DateTime fechaInicio=new DateTime(anio,mes,1);
           
           DateTime fechaFin=fechaInicio.AddMonths(1).AddDays(-1);

          
           // documentos
           List<KardexValRPT> listaDoc = this.loadKardexValRPT(fechaInicio, fechaFin, idAlmacen);
         
           foreach (var item in listaDoc)
           {
              
               SaldosKardexItemDoc nuevo = new SaldosKardexItemDoc(anio,
                                                   mes,
                                                   idAlmacen,
                                                   item.idInsumo,
                                                   item.idOrigen,
                                                   item.tipoOrigen,
                                                   item.codigo,
                                                   item.insumo,
                                                   item.unidad,
                                                   item.fecha,
                                                   item.documento,
                                                   item.numero,
                                                   item.motivo,
                                                   item.entrada,
                                                   item.salida,
                                                   item.stock,
                                                   item.precioUnit,
                                                   item.ingresoP,
                                                   item.egresoP,
                                                   item.saldo,
                                                   item.observacion,
                                                   item.idProveedor,
                                                   item.proveedor);
             

               saldok.SaldosKardexItemDocs.Add(nuevo);       
           }
           // guardar los saldos segun el cierre del mes
           List<KardexValResuRPT> lista = this.GetKardexValResuFromListDetalle(listaDoc);
           foreach (var item in lista)
           {


               SaldosKardexItem nuevo = new SaldosKardexItem(
                    item.idInsumo,
                    anio,
                    mes,
                    idAlmacen,
                    (item.stock==0?0: item.saldo/ item.stock),
                    item.codigo,
                    item.descripcion,
                    item.unidad,
                    item.inicial,
                    item.entrada,
                    item.salida,
                    item.inicialP,
                    item.ingresoP,
                    item.egresoP,
                    item.saldo,
                    item.stock
                    );
                saldok.SaldosKardexItems.Add(nuevo);
           }
           using (TransactionScope ts = new TransactionScope())
           {
               dbGestionDataContext _db = new dbGestionDataContext(Parametros.strConnString);
               int idEmpleadoEmisor = int.Parse(System.Web.HttpContext.Current.Session["idEmpleado"].ToString());
               //verificamos que no exista
               var kexist = from p in _db.SaldoKardexes
                            where p.idAlmacen == idAlmacen & p.anio == anio & p.mes == mes
                            select p;
               if (kexist.Count() > 0)
               {
                   throw new Exception("Existe Cierre");
               }

               saldok.Add(_db,
               anio,
               mes,
               idAlmacen,
               DateTime.Now,
               tipoCambiodollarCierre,
               observacion,
               idEmpleadoEmisor,
               lista.Sum(p => p.saldo));
            _db.SubmitChanges();
               // saltos
            //var pp = from a in _db.SaldosKardexItems
            //        where a.anio == anio
            //        & a.mes == mes
            //        & a.idAlmacen == idAlmacen
            //        select a;

            //if (pp.Count() > 0)
            //    saldok.totalSaldo = pp.Sum(p => p.saldo);

            //_db.SubmitChanges();
            ts.Complete();

               //apartir de aqui se maneja con dos digitos ,leo que se tiene en db

               
           }
           //lote de datos, para evitar bloq de tablas
    }


       public void DeleteCierre(short anio,
                              short mes,
                              int idAlmacen)
       {
           using (TransactionScope ts = new TransactionScope())
           {
               dbGestionDataContext _db= new dbGestionDataContext(Parametros.strConnString);


               if (idAlmacen == 4 & anio == 2011 & mes == 12)
               {
                   throw new Exception("No puedes eliminar Inventario 2011,Saldos Cargados");
               }
               if (idAlmacen == 12 & anio == 2011 & mes == 12)
               {
                   throw new Exception("No puedes eliminar Inventario 2011,Saldos Cargados");
               }


               SaldoKardex sl = _db.SaldoKardexes.Single(p => p.idAlmacen == idAlmacen & p.anio == anio & p.mes == mes);
               var slitem = from a in _db.SaldosKardexItems
                            where a.idAlmacen==idAlmacen &
                            a.anio==anio &
                            a.mes==mes
                            select a;
               //eliminamos los items del cierre
               _db.SaldosKardexItems.DeleteAllOnSubmit(slitem);

               var slitemdoc = from a in _db.SaldosKardexItemDocs
                               where a.idAlmacen == idAlmacen &
                              a.anio == anio &
                              a.mes == mes
                               select a;

               _db.SaldosKardexItemDocs.DeleteAllOnSubmit(slitemdoc);

               _db.SaldoKardexes.DeleteOnSubmit(sl);

               _db.SubmitChanges();
               ts.Complete();

           }

       }




      

       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public IEnumerable<SaldoKardexListInfo> GetCierreList(int idAlmacen, int startRowIndex, int maximumRows, string sortExpression)
       {
           DateTime fecha = DateTime.Now;
           DateTime fechaant = fecha.AddMonths(-1);

           var q2 = from a in DbUtil.Db.SaldoKardexes
                    where a.idAlmacen == idAlmacen
                    select new SaldoKardexListInfo
                    {
                        idAlmacen = a.idAlmacen,
                        almacen = a.Almacen.descripcion,
                        anio = a.anio,
                        mes = a.mes,
                        fechaCierre=a.fechaCierre,
                        fechaCierreSrt=a.fechaCierre.ToShortDateString(),
                        observacion = a.observacion,
                        tipoCambioDollarCierre = a.tipoCambioDollarCierre
                    };

           _count = q2.Count();
           q2 = ApplySort(q2, sortExpression);
           return q2.Skip(startRowIndex).Take(maximumRows);


       }



       private IQueryable<SaldoKardexListInfo> ApplySort(IQueryable<SaldoKardexListInfo> q, string sortExpression)
       {
           switch (sortExpression)
           {
               case "anio":
                   q = q.OrderBy(b => b.mes).OrderBy(b => b.anio);
                   break;
               case "anio DESC":
                   q = q.OrderByDescending(b => b.anio);
                   break;
               case "mes":
                   q = q.OrderBy(b => b.mes);
                   break;
               case "mes DESC":
                   q = q.OrderByDescending(b => b.mes);
                   break;
               case "almacen":
                   q = q.OrderBy(b => b.almacen);
                   break;
               case "almacen DESC":
                   q = q.OrderByDescending(b => b.almacen);
                   break;
               case "tipoCambiodollarCierre":
                   q = q.OrderBy(b => b.tipoCambioDollarCierre);
                   break;
               case "tipoCambioDollarCierre DESC":
                   q = q.OrderByDescending(b => b.tipoCambioDollarCierre);
                   break;
               default:
                   q = q.OrderByDescending(p => p.mes).OrderByDescending(p => p.anio);
                   break;



           }
           return q;
       }


       public List<KardexValRPT> GetCierreValRPT(short anio,
                                                  short mes,
                                                   int idAlmacen
                                                    )
       {
           DateTime inicio = new DateTime(anio, mes, 1);
           DateTime fin = inicio.AddMonths(1).AddDays(-1);


           int idEmpresa = DbUtil.Db.Almacens.Single(p => p.idInternal == idAlmacen).idEmpresa.Value;
            byte[] imagen = Parametros.GetLogoEmpresa(idEmpresa);

           var q = from a in DbUtil.Db.SaldosKardexItemDocs
                   where a.anio == anio & a.mes == mes & a.idAlmacen == idAlmacen
                   select new KardexValRPT
                   {
                       almacen = a.Almacen.descripcion,
                       codigo = a.codigo,
                       documento = a.doc,
                       egresoP = a.egreso,
                       entrada = a.entrada,
                       fecha = a.fecha,
                       fechaFinStr = fin.ToShortDateString(),
                       fechaInicioStr = inicio.ToShortDateString(),
                       fechaStr = a.fecha.ToShortDateString(),
                       idInsumo = a.idInsumo,
                       idOrigen = a.idOrigen,
                       idProveedor = (a.idProveedor==null?0:a.idProveedor.Value),
                       ingresoP = a.ingreso,
                       insumo = a.descripcion,
                       LogoEmpresa = imagen,
                       motivo = a.motivo,
                       numero = a.numero,
                       obra = a.Almacen.Obra.descripcion,
                       observacion = a.observacion,
                       precioUnit = a.precioUnit,
                       proveedor = a.Proveedor,
                       saldo = a.saldo,
                       salida = a.salida,
                       stock = a.stock,
                       tipoCambioDollar = a.SaldoKardex.tipoCambioDollarCierre,
                       tipoOrigen = a.tipoOrigen,
                       unidad = a.unidad,
                       titulo = "CIERRE KARDEX",
                   };

             q = q.OrderBy(y=>y.tipoOrigen).OrderBy(y=>y.fecha).OrderBy(p=>p.idInsumo);

           return q.ToList();


       }


       public List<KardexValResuRPT> GetCierreValResuRPT(short anio,
                                                 short mes,
                                                  int idAlmacen
                                                   )
       {
           DateTime inicio = new DateTime(anio, mes, 1);
           DateTime fin = inicio.AddMonths(1).AddDays(-1);

           
           int idEmpresa = DbUtil.Db.Almacens.Single(p => p.idInternal == idAlmacen).idEmpresa.Value;
            byte[] imagen = Parametros.GetLogoEmpresa(idEmpresa);

           var q = from a in DbUtil.Db.SaldosKardexItems
                   where a.anio == anio & a.mes == mes & a.idAlmacen == idAlmacen
                   select new KardexValResuRPT
                   {
                       almacen=a.Almacen.descripcion,
                       codigo=a.codigo,
                       descripcion=a.descripcion,
                       egresoP=a.egresoP,
                       entrada=a.entrada,
                       fechaFinStr = fin.ToShortDateString(),
                       fechaInicioStr=inicio.ToShortDateString(),
                       idInsumo=a.idInsumo,
                       ingresoP=a.ingresoP,
                       inicial=a.inicial,
                       inicialP=a.inicialP,
                       LogoEmpresa = imagen,
                       obra=a.Almacen.Obra.descripcion,
                       saldo=a.saldo,
                       salida=a.salida,
                       stock=a.cantidad,
                       titulo="CIERRE KARDEX",
                       unidad=a.unidad,
                       subFamila=a.Insumo.Insumo1.descripcion,
                       familia=a.Insumo.Insumo1.Insumo1.descripcion,
                     //  precioUnitario=a.precioUnitCierre,
                   };
           return q.OrderBy(p=>p.descripcion).ToList();

       }




         [DataObjectMethod(DataObjectMethodType.Select, false)]
       public IEnumerable<ProyectoValListInfo> GetKardexValProyectoRPT(int idEmpresa,
                                                            int startRowIndex, 
                                                            int maximumRows, 
                                                            string sortExpression)
       {

             int idEmpleado= int.Parse(System.Web.HttpContext.Current.Session["idEmpleado"].ToString());
         
             //byte[] imagen = Parametros.GetLogoEmpresa(idEmpresa);

         

         //var habiproy = from x in DbUtil.Db.EmpleadoObra
         //          where x.idEmpleado == idEmpleado & x.Obra.Proyecto.idEmpresa == idEmpresa
         //          select x.Obra.idProyecto;


         var rtodos = from a in DbUtil.Db.SaldoKardexes
                      where (idEmpresa==0? a.Almacen.idEmpresa!=0: a.Almacen.idEmpresa== idEmpresa)
                      select new 

                 {
                     idProyecto = a.Almacen.Obra.idProyecto.Value,
                     descripcion = a.Almacen.Obra.Proyecto.descripcion,
                     anio = a.anio,
                     mes = a.mes,
                     totalSaldo = a.totalSaldo
                 };

         var wq = from w in rtodos
                  group w by  new {w.anio, w.mes,w.idProyecto} into g
                  select new ProyectoValListInfo
                   {
                       idProyecto = g.First().idProyecto,
                       descripcion = g.First().descripcion,
                       anio = g.First().anio,
                       mes = g.First().mes,
                       SaldoActual = "{0} {1:N}".Fmt("S/.", g.Sum(p => p.totalSaldo))
                   };


         _count = wq.Count();
               //r = ApplySort(r, sortExpression);
         return wq.OrderByDescending(p=>p.mes).OrderByDescending(p=>p.anio).Skip(startRowIndex).Take(maximumRows);



       }





       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public List<KardexValProyectoRPT> loadKardexValProyectoRPT(int anio,
                                                       int mes,
                                                       int idProyecto)
       {
            int idEmpresa = DbUtil.Db.Proyectos.Single(p => p.idInternal == idProyecto).idEmpresa.Value;
            byte[] imagen = Parametros.GetLogoEmpresa(idEmpresa);

            var q= from a in DbUtil.Db.SaldoKardexes
                  where a.Almacen.Obra.idProyecto==idProyecto
                  & a.anio==anio
                  & a.mes==mes
                  select new KardexValProyectoRPT
                   {
                       codigo=a.Almacen.Obra.codigo,
                       egresoP=a.SaldosKardexItems.Sum(p=>p.egresoP),
                       ingresoP=a.SaldosKardexItems.Sum(p=>p.ingresoP),
                       inicialP=a.SaldosKardexItems.Sum(p=>p.inicialP),
                       LogoEmpresa = imagen,
                       obra=a.Almacen.Obra.descripcion,
                       saldo=a.SaldosKardexItems.Sum(p=>p.saldo),
                       anio=a.anio,
                       mes=a.mes,
                       tipoProyecto=a.Almacen.Obra.TipoObra.descripcion
                       };
           
           // realizamos el  resumen
           return q.ToList();

       }




       public decimal GetTipoCambioUltimoCierre(int anio, int mes)
       {
           return 0;
       }

       #endregion

      



       private DateTime? GetFechaUltingFind(int idInsumo,
                                                    int idAlmacen,
                                                    DateTime fechainicio,
                                                    int vecesatras)
       {
            DateTime? fechaFind=fechainicio.AddMonths(-1);
            vecesatras = vecesatras - 1;
            if (vecesatras == 0) { return null; }
            
           var q1 = from b in DbUtil.Db.SaldosKardexItems
                     where b.idInsumo == idInsumo &
                      b.idAlmacen == idAlmacen &
                      b.mes == fechaFind.Value.Month &
                      b.anio == fechaFind.Value.Year
                      
                     select b;

            if (q1.Count()==0)
            {
                fechaFind = this.GetFechaUltingFind(idInsumo, idAlmacen, fechaFind.Value, vecesatras);
            }

           return fechaFind;
           


       }

       //private KardexValRPT addNewIngresoSaldo(int idInsumo, decimal cantidad, decimal preciounidad, DateTime fecha)
       //{
       //    KardexValRPT k = new KardexValRPT();

       

       //    return k;
       //}


       //[DataObjectMethod(DataObjectMethodType.Select, false)]
       //public List<KardexValRPT> loadKardexValRPT(DateTime fechaInicio, DateTime fechaFin, int idAlmacen)
       //{
       //    //logo de la empresa


       //    int idEmpresa = DbUtil.Db.Almacens.Single(p => p.idInternal == idAlmacen).idEmpresa.Value;
       //    string archivoLogo = DbUtil.Db.Empresa.Single(p => p.idInternal == idEmpresa).Logo;

       //    if (archivoLogo == null | archivoLogo.Trim() == String.Empty)
       //    {
       //        throw new Exception("No existe Logo de la Empresa");
       //    }



       //    string rutaLogo = System.Web.HttpContext.Current.Server.MapPath("../App_Data/Empresa/Logo/" + archivoLogo);

       //    byte[] imagen = UtilityExtensions.Util.FileToBytesImage(rutaLogo);



       //    //traemos los saldos iniciales  segun los ultimos movimientos
       //    //select  idalmacen,idInsumo,max(anio),max(mes) 
       //    // from saldosKardex 
       //    // group by idalmacen,idInsumo



       //    var qp = (from a in DbUtil.Db.view_KardexItems
       //              where a.fecha.Value>=fechaInicio & a.fecha.Value<=fechaFin
       //              select new KardexValRPT
       //              {
       //                  almacen=a.almacen,
       //                  documento=a.documento,
       //                  egresoP=a.egresoP,
       //                  entrada=a.entrada.Value,
       //                  fecha=a.fecha.Value,
       //                  fechaFinStr = fechaFin.ToShortDateString(),
       //                  fechaInicioStr = fechaInicio.ToShortDateString(),
       //                  fechaStr=a.fecha.Value.ToShortDateString(),
       //                  ingresoP=a.ingresoP.Value,
       //                  codigo=a.codigo,
       //                  insumo=a.insumo,
       //                  unidad=a.unidad,
       //                  LogoEmpresa=imagen,
       //                  motivo=a.motivo,
       //                  numero=a.numero,
       //                  obra=a.obra,
       //                  observacion=a.observacion,
       //                  precioUnit=a.precioUnit.Value,
       //                  proveedor=a.proveedor,
       //                  saldo=a.saldo,
       //                  salida=a.salida,
       //                  stock=a.stock.Value,
       //                  tipoCambioDollar=a.tipoCambioDollar.Value,
       //                  idInsumo=a.idInsumo,
       //                  tipoOrigen=a.tipoOrigen,
       //                  }).OrderBy(w => w.fecha);

       //        decimal acumuladaCantAnt=0; //cierre anterior
       //        decimal acumuladaPrecioAnt=0;
       //        int idInsumo=0;

       //        var lista = qp.ToList();
       //        foreach (var item in lista)
       //         {
       //            //control de stock cantidad por grupo
       //            // verificamos que el insumo es el mismo que el anterio para resetvalores
       //             if (idInsumo == 0) { 
       //                 //primera fila del insumo
                        
       //                 idInsumo=item.idInsumo;
       //                 //informacion del  ultimo cierre
       //                 item.inicial = 0;
       //                 item.inicialP = 0;
       //                 DateTime? fechaFind=this.GetFechaUltingFind(idInsumo,idAlmacen,item.fecha,5);
       //                 if (fechaFind.HasValue)
       //                 {
       //                 SaldosKardexItem var=DbUtil.Db.SaldosKardexItems.Single(p=>p.idAlmacen==idAlmacen &
       //                                                                     p.anio==fechaFind.Value.Year &
       //                                                                     p.mes==fechaFind.Value.Month &
       //                                                                     p.idInsumo==idInsumo);
       //                     // si este es el caso entoces creamos un item con la informacion 
       //                     // de este.
       //                     item.inicial=var.cantidad;
       //                     item.inicialP = var.precioUnitCierre;
       //                     // debe existir un valor inicial como ingreso
       //                     //addNewIngresoSaldo(idInsumo, item.inicial, item.inicialP,fecha.);
       //                     KardexValRPT k = item; //clonamos uno nuevo;
       //                     // creamos una lista de saldos iniciales

       //                 }
       //                 acumuladaCantAnt = 0;
       //                 acumuladaPrecioAnt = 0;
       //             }
       //            // lista.Add(addNewIngresoSaldo);

       //            //calculo del precio  primero si es Salida
       //            if(item.tipoOrigen==2)
       //            {
       //                // salida de mercaderia
       //                item.precioUnit = acumuladaPrecioAnt / acumuladaCantAnt;
       //                 item.egresoP = item.salida * item.precioUnit;
       //            }

       //            item.stock = acumuladaCantAnt + item.entrada - item.salida;
       //            acumuladaCantAnt = item.stock;
       //            //control de stock monedaBase
       //            item.ingresoP = item.entrada * item.precioUnit;

       //            item.saldo = acumuladaPrecioAnt + item.ingresoP - item.egresoP;
       //            acumuladaPrecioAnt = item.saldo;

       //         }



       //        return lista;
       //    }


       #region "Valorizado del Kardex"

       //private IQueryable<KardexValRPT> ApplySort(IQueryable<KardexValRPT> q, string sortExpression)
       //{
       //    switch (sortExpression)
       //    {
       //        case "tipoOrigen":
       //            q = q.OrderBy(b => b.fecha).OrderBy(b => b.tipoOrigen);
       //            break;
       //        case "tipoOrigen DESC":
       //            q = q.OrderByDescending(b => b.tipoOrigen);
       //            break;
       //        case "documento":
       //            q = q.OrderBy(b => b.documento);
       //            break;
       //        case "documento DESC":
       //            q = q.OrderByDescending(b => b.documento);
       //            break;
       //        case "entrada":
       //            q = q.OrderBy(b => b.entrada);
       //            break;
       //        case "entrada DESC":
       //            q = q.OrderByDescending(b => b.entrada);
       //            break;
       //        case "motivo":
       //            q = q.OrderBy(b => b.motivo);
       //            break;
       //        case "motivo DESC":
       //            q = q.OrderByDescending(b => b.motivo);
       //            break;
       //        case "observacion":
       //            q = q.OrderBy(b => b.observacion);
       //            break;
       //        case "observacion DESC":
       //            q = q.OrderByDescending(b => b.observacion);
       //            break;
       //        case "proveedor":
       //            q = q.OrderBy(b => b.proveedor);
       //            break;
       //        case "proveedor DESC":
       //            q = q.OrderByDescending(b => b.proveedor);
       //            break;
       //        case "salida":
       //            q = q.OrderBy(b => b.salida);
       //            break;
       //        case "salida DESC":
       //            q = q.OrderByDescending(b => b.salida);
       //            break;
               
       //        default:
       //            q = q.OrderByDescending(p => p.tipoOrigen).OrderByDescending(p => p.fecha);
       //            break;

       //    }
       //    return q;
       //}




       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public IEnumerable<KardexValRPT> GetKardexMovimientoInsumo(int idInsumo,
                                                                           int idAlmacen, 
                                                                           DateTime fechaInicio,
                                                                           DateTime fechaFin,
                                                                           int startRowIndex, 
                                                                           int maximumRows, 
                                                                           string sortExpression)
       {
           var lista=this.loadKardexValRPT(fechaInicio,fechaFin,idAlmacen);


           var q = lista.Where(p=>p.idInsumo==idInsumo);
                   
           _count = q.Count();
           //q = ApplySort(q.AsQueryable(), sortExpression); //por el movimiento no puede estaar ordenado
           return q.Skip(startRowIndex).Take(maximumRows);
           
       }




       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public List<KardexValRPT> loadKardexValRPT(DateTime fechaInicio, 
                                                   DateTime fechaFin, 
                                                   int idAlmacen)
       {

           //logo de la empresa


           int idEmpresa = DbUtil.Db.Almacens.Single(p => p.idInternal == idAlmacen).idEmpresa.Value;


           byte[] imagen = Parametros.GetLogoEmpresa(idEmpresa);



           
        //saldos iniciales
           //1.- los insumo que ingresan al calculo  /solo  los que tienen movimiento
           var q= (from a in DbUtil.Db.NotaIngresoItems
                  where a.NotaIngreso.idAlmacen==idAlmacen & 
                  a.NotaIngreso.fecha.Value>=fechaInicio & a.NotaIngreso.fecha<=fechaFin
                  select a.idInsumo).Distinct();
           
           var pp= (from b in DbUtil.Db.NotaSalidaItems
                  where b.NotaSalida.idAlmacen==idAlmacen &
                  b.NotaSalida.fecha>=fechaInicio & b.NotaSalida.fecha<=fechaFin
                  select b.idInsumo).Distinct();

         //  var qp=q.Concat(pp).Distinct();

           //2.- los valores desde el ultimo cierre solo de los insumos con movimiento
           // y menores a la fecha de esta consulta //qp.Contains(a.idInsumo) &
           
           
           DateTime fechaant=fechaInicio.AddMonths(-1);

          

           var w= from a in DbUtil.Db.SaldosKardexItems
                  where a.idAlmacen == idAlmacen & a.anio == fechaant.Year &
                  a.mes== fechaant.Month       &         
                  a.cantidad>0
                  group a by a.idInsumo into g
                  select new 
                    {
                    idInsumo=g.Key,
                    anio=g.Max(x=>x.anio),
                    mes=g.Max(y=>y.mes)
                    };
           //3.- Estos Valores deben de ingresar  como saldo iniciales al kardex
           //traemos los movimientos y juntamos  con los saldos iniciales

           //solo para el caso de las obras de PEZET,DAMMET,

           //var w = from a in DbUtil.Db.SaldosKardexItems
           //        where a.idAlmacen == idAlmacen & a.anio == fechaant.Year &
           //        a.mes == fechaant.Month &
           //        a.cantidad > 0
           //        group a by a.idInsumo into g
           //        select new
           //        {
           //            idInsumo = g.Key,
           //            anio = g.Max(x => x.anio),
           //            mes = g.Max(y => y.mes)
           //        };


           //---------------------------------------------


           var s = (from a in DbUtil.Db.view_KardexItems
                     where a.fecha.Value>=fechaInicio & a.fecha.Value<=fechaFin & a.idAlmacen==idAlmacen
                     
                    select new KardexValRPT
                     {
                         almacen = a.almacen,
                         idOrigen=a.idOrigen,
                         idProveedor=(a.idProveedor==null?0:a.idProveedor.Value),
                         codigo = a.codigo,
                         insumo = a.insumo,
                         unidad = a.unidad,
                         familia=a.familia,
                         subFamilia=a.subfamilia,
                         obra = a.obra,
                         //-----------------
                         documento=a.documento,
                         egresoP=Convert.ToDecimal(a.egresoP),
                         entrada=Convert.ToDecimal(a.entrada.Value),
                         fecha=a.fecha.Value,
                         ingresoP=Convert.ToDecimal(a.ingresoP.Value),
                         motivo=a.motivo,
                         numero=a.numero,
                         observacion=a.observacion,
                         precioUnit=Convert.ToDecimal(a.precioUnit.Value),
                        
                         proveedor=a.proveedor,
                         saldo=Convert.ToDecimal(a.saldo),
                         salida = Convert.ToDecimal(a.salida),
                         stock = Convert.ToDecimal(a.stock.Value),

                         tipoCambioDollar=Convert.ToDecimal(a.tipoCambioDollar.Value),
                         idInsumo=a.idInsumo,
                         tipoOrigen=Convert.ToInt16(a.tipoOrigen),
                         nota=a.nota,
                         idObra=a.idObra.Value,
                         idNota=a.idNota.Value,
                         });

           //fecha  de inicioCierre
           DateTime inicioCierre = new DateTime(fechaInicio.Year, fechaInicio.Month, 1);
           string inicioCierreStr = inicioCierre.ToShortDateString();
           decimal cero=0;
           var t = (from a in DbUtil.Db.SaldosKardexItems
                    join b in w on
                    new { a.idInsumo, a.anio, a.mes } equals new { b.idInsumo, b.anio, b.mes }
                    where a.idAlmacen==idAlmacen
                    select new KardexValRPT
                    {

                        almacen = a.Almacen.descripcion,
                        idOrigen = 0,
                        idProveedor = 0,
                        codigo = a.Insumo.codigo,
                        insumo = a.Insumo.descripcion,
                        unidad = a.Insumo.InsumoUnidad.abreviacion,
                       
                        obra = a.Almacen.Obra.descripcion,

                        documento = "INI",
                        egresoP = Convert.ToDecimal(cero),
                        entrada = Convert.ToDecimal(a.cantidad),
                        fecha = Convert.ToDateTime(inicioCierre),
                        subFamilia=a.Insumo.Insumo1.descripcion,
                        familia=a.Insumo.Insumo1.Insumo1.descripcion,
                        motivo = "INICIO",
                        numero = "INICIO",
                        observacion = "INICIO",
                        precioUnit = Convert.ToDecimal(a.precioUnitCierre),

                        proveedor = "INICIO",
                        saldo =Convert.ToDecimal(a.precioUnitCierre * a.cantidad),
                        salida = Convert.ToDecimal(cero),
                        
                        stock  =  Convert.ToDecimal(a.cantidad-cero),
                        ingresoP = Convert.ToDecimal(a.precioUnitCierre * a.cantidad-cero),
                        
                        tipoCambioDollar =Convert.ToDecimal(a.SaldoKardex.tipoCambioDollarCierre),
                        idInsumo = a.idInsumo,
                        tipoOrigen = Convert.ToInt16(0),
                        nota = "INICIO",
                        idObra=0,
                        idNota = 0
                       
                    }); //para los saldos iniciales



           //4.-st.union

           var qq = s.Concat(t).OrderBy(y=>y.tipoOrigen).OrderBy(y=>y.fecha).OrderBy(p=>p.codigo);

           // creamos los saldos con respecto a su anterios segun orden de fecha
           List<KardexValRPT> lista = qq.ToList();

           int idInsumo = 0;
           decimal acumuladaCantAnt = 0;
           decimal acumuladaPrecioAnt = 0;
           foreach (var item in lista)
           {
               item.fechaFinStr =Convert.ToString(fechaFin.ToShortDateString());
               item.fechaInicioStr = Convert.ToString(fechaInicio.ToShortDateString());
               item.fechaStr = Convert.ToString(item.fecha.ToShortDateString());
               item.LogoEmpresa = imagen;
               item.titulo = "";
               //control de stock cantidad por grupo
               // verificamos que el insumo es el mismo que el anterio para resetvalores
               if (idInsumo != item.idInsumo)
               {
                   //primera fila del insumo inicializamos valores
                   idInsumo = item.idInsumo;
                   acumuladaCantAnt = 0;
                   acumuladaPrecioAnt = 0;
                   
               }
               
               //calculo del precio  primero si es Salida
               if (item.tipoOrigen == 2)
               {
                   // salida de mercaderia
                   item.precioUnit = 0;
                  

                   if (acumuladaCantAnt != 0)
                   {
                       item.precioUnit = Math.Round(acumuladaPrecioAnt / acumuladaCantAnt,4);
                   }
                   item.egresoP = Math.Round(item.salida * item.precioUnit,4);
               }

               decimal Stock = (acumuladaCantAnt + item.entrada - item.salida);
               item.stock = Stock;
               acumuladaCantAnt = item.stock;
               //control de stock monedaBase
               item.ingresoP = Math.Round(item.entrada * item.precioUnit,4);

               item.saldo = acumuladaPrecioAnt + item.ingresoP - item.egresoP;
               acumuladaPrecioAnt = item.saldo;

           }

           return lista.OrderBy(p=>p.insumo).ToList();

       }
    
       
      
       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public List<KardexValResuRPT> loadKardexValResuRPT(DateTime fechaInicio,
                                                       DateTime fechaFin,
                                                       int idAlmacen)
       {
           
           
           //tomamos del detalle

           List<KardexValRPT> items = this.loadKardexValRPT(fechaInicio, fechaFin, idAlmacen);
           
          
           // realizamos el  resumen
           return GetKardexValResuFromListDetalle(items);

           }




      
      

      
       private List<KardexValResuRPT> GetKardexValResuFromListDetalle(List<KardexValRPT> items)
       {
           var qqq = items.Where(p => p.idInsumo == 236);
           if (qqq.Count() > 0)
           {
               decimal total = qqq.Sum(p => p.ingresoP);

           }

            var q = from a in items
                  group a by a.idInsumo into g
                  select  new KardexValResuRPT
                  {

                      inicial = g.Where(p => p.tipoOrigen == 0).Sum(p => p.entrada),
                      inicialP = g.Where(p => p.tipoOrigen == 0).Sum(p => p.ingresoP),

                      
                      entrada = g.Where(p => p.tipoOrigen == 1).Sum(p => p.entrada),
                      salida = g.Where(p => p.tipoOrigen == 2).Sum(p => p.salida),
                      
                      ingresoP = g.Where(p => p.tipoOrigen == 1).Sum(p => p.ingresoP),
                      egresoP = g.Where(p => p.tipoOrigen == 2).Sum(p => p.egresoP),

                      stock =
                      g.Where(p => p.tipoOrigen == 0).Sum(p => p.entrada)+
                      g.Where(p => p.tipoOrigen == 1).Sum(p => p.entrada)-
                       g.Where(p => p.tipoOrigen == 2).Sum(p => p.salida),


                      saldo=
                      g.Where(p => p.tipoOrigen == 0).Sum(p => p.ingresoP)+
                      g.Where(p => p.tipoOrigen == 1).Sum(p => p.ingresoP)-
                      g.Where(p => p.tipoOrigen == 2).Sum(p => p.egresoP),



                      fechaFinStr = g.First().fechaFinStr,
                      fechaInicioStr=g.First().fechaInicioStr,
                      LogoEmpresa=g.First().LogoEmpresa,
                      codigo=g.First().codigo,
                      descripcion = g.First().insumo,
                      unidad=g.First().unidad,
                      almacen=g.First().almacen,
                      obra=g.First().obra,
                      idInsumo=g.First().idInsumo,
                      familia=g.First().familia,
                      subFamila=g.First().subFamilia,
                      //precioUnitario = (g.Where(p => p.tipoOrigen == 0).Sum(p => p.ingresoP) +
                      //g.Where(p => p.tipoOrigen == 1).Sum(p => p.ingresoP) -
                      //g.Where(p => p.tipoOrigen == 2).Sum(p => p.egresoP)
                      //              == 0 ? 0 :

                      //              g.Where(p => p.tipoOrigen == 0).Sum(p => p.ingresoP) +
                      //g.Where(p => p.tipoOrigen == 1).Sum(p => p.ingresoP) -
                      //g.Where(p => p.tipoOrigen == 2).Sum(p => p.egresoP) /
                      
                      //g.Where(p => p.tipoOrigen == 0).Sum(p => p.entrada) +
                      //g.Where(p => p.tipoOrigen == 1).Sum(p => p.entrada) -
                      // g.Where(p => p.tipoOrigen == 2).Sum(p => p.salida)),
                      //mejorar luego
                      //precioUnitario = (item.stock == 0 ? 0 : item.saldo / item.stock),
                    };

           return  q.ToList();
       }

    
     

       


       int _count;

       public int Count(int idInsumo,int idAlmacen,DateTime fechaInicio,DateTime fechaFin,  int startRowIndex, int maximumRows, string sortExpression)
       {
           return _count;
       }

        public int Count(int idAlmacen,string prefixText, int startRowIndex, int maximumRows, string sortExpression)
       {
           return _count;
       }
       public int Count(int idAlmacen, int startRowIndex, int maximumRows, string sortExpression)
       {
           return _count;
       }



       public int Count(int startRowIndex, int maximumRows, string sortExpression, int idEmpresa)
       {
           return _count;
       }
       private IQueryable<KardexListRPT> ApplySort(IQueryable<KardexListRPT> q, string sortExpression)
       {
           switch (sortExpression)
           {
               case "codigo":
                   q = q.OrderBy(b => b.codigo);
                   break;
               case "codigo DESC":
                   q = q.OrderByDescending(b => b.codigo);
                   break;
               case "Descripcion":
                   q = q.OrderBy(b => b.descripcion);
                   break;
               case "Descripcion DESC":
                   q = q.OrderByDescending(b => b.descripcion);
                   break;
               case "unidad":
                   q = q.OrderBy(b => b.unidad);
                   break;
               case "unidad DESC":
                   q = q.OrderByDescending(b => b.unidad);
                   break;
               case "mes":
                   q = q.OrderBy(b => b.mes);
                   break;
               case "mes DESC":
                   q = q.OrderByDescending(b => b.mes);
                   break;

               case "cantidadIng":
                   q = q.OrderBy(b => b.cantidadIng);
                   break;
               case "cantidadIng DESC":
                   q = q.OrderByDescending(b => b.cantidadIng);
                   break;

               case "cantidadSal":
                   q = q.OrderBy(b => b.cantidadSal);
                   break;
               case "cantidadSal DESC":
                   q = q.OrderByDescending(b => b.cantidadSal);
                   break;

               case "stock":
                   q = q.OrderBy(b => b.stock);
                   break;
               case "stock DESC":
                   q = q.OrderByDescending(b => b.stock);
                   break;

                   


           }
           return q;
       }

   #endregion
        
        #region "SALDO Actual"

       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public IEnumerable<KardexListRPT> getSaldoActualList(int idAlmacen,
                                                            
                                                            int startRowIndex, 
                                                            int maximumRows, 
                                                            string sortExpression, string prefixText = null)
       {
           //actualizar cambios en ambos metodos
           if (!prefixText.HasValue())
               prefixText = "";

           DateTime fechaActual = DateTime.Now;
           DateTime fechainicio = new DateTime(fechaActual.Year, fechaActual.Month, 1);
           DateTime FechaCierreAnt = fechainicio.AddMonths(-1);

           //saldos iniciales
           //1.- los insumo que ingresan al calculo  /solo  los que tienen movimiento
           var q = (from a in DbUtil.Db.NotaIngresoItems
                    where a.NotaIngreso.idAlmacen == idAlmacen &

                    a.NotaIngreso.fecha.Value >= fechainicio & a.NotaIngreso.fecha <= fechaActual
                    select a.idInsumo).Distinct();

           var pp = (from b in DbUtil.Db.NotaSalidaItems
                     where b.NotaSalida.idAlmacen == idAlmacen &
                     b.NotaSalida.fecha >= fechainicio & b.NotaSalida.fecha <= fechaActual
                     select b.idInsumo).Distinct();

           var qp = q.Concat(pp).Distinct();

           //2.- los valores desde el ultimo cierre solo de los insumos con movimiento

           var w = from a in DbUtil.Db.SaldosKardexItems
                   where a.idAlmacen == idAlmacen & qp.Contains(a.idInsumo)
                    group a by a.idInsumo into g
                   select new
                     {
                         idInsumo = g.Key,
                         anio = g.Max(x => x.anio),
                         mes = g.Max(y => y.mes)
                     };

           //------- SALDOS INICIALES Inner JOIN
           //error en este code:
           //into viewKardex
           //from c in viewKardex.DefaultIfEmpty()

           var t = (from a in DbUtil.Db.SaldosKardexItems
                    join b in w on
                    new { a.idInsumo, a.anio, a.mes } equals new { b.idInsumo, b.anio, b.mes }
                    where a.idAlmacen == idAlmacen
                    & (a.codigo + a.descripcion.ToUpper()).Contains(prefixText.ToUpper())
                    select new
                    {
                        idinsumo = a.idInsumo,
                        codigo = a.Insumo.codigo,
                        descripcion = a.Insumo.descripcion,
                        unidad = a.Insumo.InsumoUnidad.abreviacion,
                        cantidadIni = a.cantidad

                    }); //para los saldos iniciales


           //3.- Estos Valores deben de ingresar  como saldo iniciales al kardex
           //traemos los movimientos y juntamos  con los saldos iniciales
           var s = (from a in DbUtil.Db.view_KardexItems
                    where a.fecha.Value >= fechainicio & a.fecha.Value <= fechaActual &
                   a.idAlmacen == idAlmacen
                    group a by a.idInsumo into g
                    select new
                    {
                        idInsumo = g.Key,
                        codigo = g.First().codigo,
                        descripcion = g.First().insumo,
                        unidad = g.First().unidad,
                        cantidadEnt = g.Sum(p => p.entrada.Value),
                        cantidadSal = g.Sum(p => p.salida),
                    });



           //4.- sumamos saldos inciales  Left  Join


           var r = from a in s
                   join b in t on a.idInsumo equals b.idinsumo into viewKardexfin
                   from d in viewKardexfin.DefaultIfEmpty()
                   where (a.codigo + a.descripcion.ToUpper()).Contains(prefixText.ToUpper())
                   select new KardexListRPT
                   {
                       codigo = a.codigo,
                       descripcion = a.descripcion,
                       unidad = a.unidad,
                       cantidadIng = a.cantidadEnt,
                       cantidadSal = a.cantidadSal,
                       idAlmacen = idAlmacen,
                       idInsumo = a.idInsumo,
                       cantidadIni = (d.cantidadIni == null ? 0 : d.cantidadIni),
                       stock = (d.cantidadIni == null ? 0 : d.cantidadIni) + a.cantidadEnt - a.cantidadSal
                   };

           
               //5.- agregamos lo que no se tomaron en cuenta

               ////------- SALDOS INICIALES+++


               var w_no = from a in DbUtil.Db.SaldosKardexItems
                          where
                          a.idAlmacen == idAlmacen
                          & a.anio <= FechaCierreAnt.Year
                          & a.mes <= FechaCierreAnt.Month
                          & !qp.Contains(a.idInsumo) 
                          
                          group a by a.idInsumo into g
                          select new
                          {
                              idInsumo = g.Key,
                              anio = g.Max(x => x.anio),
                              mes = g.Max(y => y.mes)
                          };


               //w los valores que no son  utilizados  INNER JOIN
               var wq = from a in DbUtil.Db.SaldosKardexItems
                         join b in w_no on
                        new {a.idInsumo,a.anio,a.mes} equals new {b.idInsumo , b.anio , b.mes  }
                        where a.idAlmacen == idAlmacen
                        & (a.codigo + a.descripcion.ToUpper()).Contains(prefixText.ToUpper())
                        & a.cantidad>0
                        select new KardexListRPT
                   {
                       codigo = a.codigo,
                       descripcion = a.descripcion,
                       unidad = a.unidad,

                       cantidadIng = Convert.ToDecimal(0),
                       cantidadSal = Convert.ToDecimal(0),
                       idAlmacen = idAlmacen,
                       idInsumo = a.idInsumo,
                       cantidadIni = a.cantidad,
                       stock = Convert.ToDecimal(a.cantidad)
                   };



               //para los saldos iniciales

               r = r.Concat(wq);

               _count = r.Count();
               r = ApplySort(r, sortExpression);
               return r.Skip(startRowIndex).Take(maximumRows);


       }



       [DataObjectMethod(DataObjectMethodType.Select, false)]
       public List<KardexListInfo> getSaldoActualList(int idAlmacen,int anio,int mes,int dia, int maximumRows,string prefixText )
       {

           DateTime fechaActual = new DateTime(anio, mes, dia);
           
           DateTime fechainicio = new DateTime(anio, mes, 1);
           DateTime FechaCierreAnt = fechainicio.AddMonths(-1);

           //saldos iniciales
           //1.- los insumo que ingresan al calculo  /solo  los que tienen movimiento
           var q = (from a in DbUtil.Db.NotaIngresoItems
                    where a.NotaIngreso.idAlmacen == idAlmacen &
                    a.NotaIngreso.fecha.Value >= fechainicio & a.NotaIngreso.fecha <= fechaActual
                    select a.idInsumo).Distinct();

           var pp = (from b in DbUtil.Db.NotaSalidaItems
                     where b.NotaSalida.idAlmacen == idAlmacen &
                     b.NotaSalida.fecha >= fechainicio & b.NotaSalida.fecha <= fechaActual
                     select b.idInsumo).Distinct();

           var qp = q.Concat(pp).Distinct();

           //2.- los valores desde el ultimo cierre solo de los insumos con movimiento del ultimo cierre
           // desl utimo 

           var w = from a in DbUtil.Db.SaldosKardexItems
                   where 
                   a.idAlmacen == idAlmacen 
                   & a.anio <= FechaCierreAnt.Year 
                   & a.mes<=FechaCierreAnt.Month
                   & qp.Contains(a.idInsumo)
                  
                   group a by a.idInsumo into g
                   select new
                   {
                       idInsumo = g.Key,
                       anio = g.Max(x => x.anio),
                       mes = g.Max(y => y.mes)
                   };

           //------- SALDOS INICIALES --- inner join 

           var t = (from a in DbUtil.Db.SaldosKardexItems
                    join b in w on
                     new { a.idInsumo, a.anio, a.mes } equals new { b.idInsumo, b.anio, b.mes }
                    
                    where a.idAlmacen == idAlmacen
                    select new
                    {
                        idinsumo = a.idInsumo,
                        codigo = a.Insumo.codigo,
                        descripcion = a.Insumo.descripcion,
                        unidad = a.Insumo.InsumoUnidad.abreviacion,
                        cantidadIni = a.cantidad

                    }); //para los saldos iniciales


           //3.- Estos Valores deben de ingresar  como saldo iniciales al kardex
           //traemos los movimientos y juntamos  con los saldos iniciales
           var s = (from a in DbUtil.Db.view_KardexItems
                    where a.fecha.Value >= fechainicio & a.fecha.Value <= fechaActual &
                   a.idAlmacen == idAlmacen
                    group a by a.idInsumo into g
                    select new
                    {
                        idInsumo = g.Key,
                        codigo = g.First().codigo,
                        descripcion = g.First().insumo,
                        unidad = g.First().unidad,
                        cantidadEnt = g.Sum(p => p.entrada.Value),
                        cantidadSal = g.Sum(p => p.salida),
                    });



           //4.- sumamos saldos inciales

              var r = from a in s
                   join b in t on a.idInsumo equals b.idinsumo into viewKardexfin
                   from d in viewKardexfin.DefaultIfEmpty()
                   where (a.codigo + a.descripcion).Contains(prefixText)
                   select new KardexListInfo
                   {
                       codigo = a.codigo,
                       descripcion = a.descripcion,
                       unidad = a.unidad,
                       cantidad = (d.cantidadIni == null ? 0 : d.cantidadIni) + a.cantidadEnt - a.cantidadSal,
                       idInsumo=a.idInsumo
                   };


           //5.- agregamos lo que no se tomaron en cuenta

              ////------- SALDOS INICIALES+++


            var w_no = from a in DbUtil.Db.SaldosKardexItems
                   where 
                   a.idAlmacen == idAlmacen 
                   & a.anio <= FechaCierreAnt.Year 
                   & a.mes<=FechaCierreAnt.Month
                   & !qp.Contains(a.idInsumo)
                  
                   group a by a.idInsumo into g
                   select new
                   {
                       idInsumo = g.Key,
                       anio = g.Max(x => x.anio),
                       mes = g.Max(y => y.mes)
                   };


             // ----------LEFT JOIN
             //         into viewKardex
             //          from c in viewKardex.DefaultIfEmpty()

           //w los valores que no son  utilizados
              var wq = from a in DbUtil.Db.SaldosKardexItems
                       join b in w_no on
                        new { a.idInsumo, a.anio, a.mes } equals new { b.idInsumo, b.anio, b.mes }
                         where a.idAlmacen == idAlmacen
                        & (a.codigo + a.descripcion).Contains(prefixText)
                         & a.cantidad > 0
                       select new KardexListInfo
                       {
                           codigo = a.codigo,
                           descripcion = a.descripcion,
                           unidad = a.unidad,
                           cantidad = a.cantidad,
                           idInsumo=a.idInsumo,
                       };

             //para los saldos iniciales

              r = r.Concat(wq).Where(p=>p.cantidad>0).Take(maximumRows);

              return r.ToList();
           

       }


       #endregion







      
    }
}
